package com.jctrip.hotel.source.service.dossen.impl;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.jctrip.hotel.common.util.AreaUtil;
import com.jctrip.hotel.domain.entity.HtHotelStdImage;
import com.jctrip.hotel.source.client.HworldCallBackClient;
import com.jctrip.hotel.source.mq.IncrHotelRocketMqProducer;
import com.jctrip.hotel.source.service.basic.HtHotelStdImageService;
import com.jctrip.hotel.source.xxl.dossen.thread.*;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jctrip.hotel.common.constant.RedisKeyConstant;
import com.jctrip.hotel.common.constant.XxlJobNameConstant;
import com.jctrip.hotel.common.enums.SourceEnum;
import com.jctrip.hotel.common.threadpool.XxlJobThreadPool;
import com.jctrip.hotel.common.util.BeanUtil;
import com.jctrip.hotel.common.util.JsonUtil;
import com.jctrip.hotel.common.util.RedisUtil;
import com.jctrip.hotel.domain.dao.HtHotelStdInfoDao;
import com.jctrip.hotel.domain.entity.HtHotelStdInfo;
import com.jctrip.hotel.domain.entity.HtPriceCalendar;
import com.jctrip.hotel.domain.entity.HtRoomTypeStdInfo;
import com.jctrip.hotel.source.model.dossen.DossenCityData;
import com.jctrip.hotel.source.model.dossen.DossenGetHotelInfoReq;
import com.jctrip.hotel.source.model.dossen.DossenGetHotelRoomTypeReq;
import com.jctrip.hotel.source.model.dossen.DossenGetPriceAndCountReq;
import com.jctrip.hotel.source.model.dossen.DossenHotelData;
import com.jctrip.hotel.source.model.dossen.DossenHotelData.BaseInfoDTO;
import com.jctrip.hotel.source.model.dossen.DossenPriceAndCountData;
import com.jctrip.hotel.source.model.dossen.DossenPriceAndCountData.ActivityResvRoomDTO;
import com.jctrip.hotel.source.model.dossen.DossenRatePlanData;
import com.jctrip.hotel.source.model.dossen.DossenRoomTypeData;
import com.jctrip.hotel.source.service.basic.HtHotelStdInfoService;
import com.jctrip.hotel.source.service.basic.HtPriceCalendarService;
import com.jctrip.hotel.source.service.basic.HtRoomTypeStdInfoService;
import com.jctrip.hotel.source.service.dossen.DossenService;
import com.jctrip.hotel.source.service.dossen.DossenTaskService;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author henry
 * @Date 2023/6/6 21:40
 * @Description
 */
@Service
@Slf4j
public class DossenTaskServiceImpl implements DossenTaskService {

    @Autowired
    private DossenService dossenService;
    @Resource
    private HtHotelStdInfoDao htHotelStdInfoDao;
    @Resource
    private HtHotelStdInfoService htHotelStdInfoService;
    @Resource
    private HtRoomTypeStdInfoService htRoomTypeStdInfoService;
    @Resource
    private HtPriceCalendarService htPriceCalendarService;
    @Resource
    private HworldCallBackClient hworldCallBackClient;
    @Autowired
    private RedisUtil redisUtil;
    @Resource
    private HtHotelStdImageService htHotelStdImageService;
    @Autowired
    private IncrHotelRocketMqProducer incrHotelRocketMqProducer;

    private static final XxlJobThreadPool syncDossenHotelIdListTaskFastPopPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_DOSSEN_HOTEL_ID_LIST_TASK_POP);
    private static final XxlJobThreadPool syncDossenRatesTaskPopPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_DOSSEN_RATES_TASK_POP);
    private static final XxlJobThreadPool syncDossenLongerRatesTaskPopPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_DOSSEN_LONGER_RATES_TASK_POP);
    private static final XxlJobThreadPool syncDossenHotspotRatesTaskPopPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_DOSSEN_HOTSPOT_RATES_TASK_POP);
    private static final XxlJobThreadPool syncDossenRoomRepairTaskPopPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_DOSSEN_ROOM_REPAIR_TASK_POP);

    private static final long PUSH_EXPIRY = 1 * 60;
    private final static Integer QPS_COUNT = 1;
    private final static Long TIME_OUT = 2000L;

    @Override
    public void syncDossenHotelIdListTaskFastPush(String appId, String key) {
        try {
            if (redisUtil.setENx(RedisKeyConstant.HOTEL_MAIN_DOSSEN_CITYID_PUSH, PUSH_EXPIRY,
                    RedisKeyConstant.HOTEL_MAIN_DOSSEN_CITYID_PUSH)) {
                List<DossenCityData> dossenCityDataList = dossenService.getCitiesList(appId, key);
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_DOSSEN_CITYID_LIST,
                        dossenCityDataList.stream().map(DossenCityData::getCityId).collect(
                                Collectors.toList()));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void syncDossenHotelIdListTaskFastPop(String appId, String key) {
        syncDossenHotelIdListTaskFastPopPool.execute(() -> new SyncDossenHotelIdTaskThread(appId, key));
    }

    @Override
    public void syncDossenHotelIdTask(String appId, String key, DossenGetHotelInfoReq getHotelInfoReq) {
        try {
            Integer pageIndex = getHotelInfoReq.getPageIndex();
            while (true) {
                if (StringUtils.isNotBlank(
                        redisUtil.acquireToken(RedisKeyConstant.HOTEL_MAIN_DOSSEN_ROOM_STATUS_LIMIT_LOCK,
                                QPS_COUNT,
                                TIME_OUT))) {
                    Page<DossenHotelData> dossenHotelDataPage = dossenService.getHotelInfo(appId, key, getHotelInfoReq);
                    if (null == dossenHotelDataPage || CollectionUtils.isEmpty(dossenHotelDataPage.getRecords())) {
                        break;
                    }

                    for (DossenHotelData dossenHotelData : dossenHotelDataPage.getRecords()) {
                        // 基础数据
                        HtHotelStdInfo htHotelStdInfo = buildHotelStdInfo(dossenHotelData);
                        htHotelStdInfoService.saveOrUpdate(htHotelStdInfo,
                                new LambdaQueryWrapper<HtHotelStdInfo>().eq(HtHotelStdInfo::getHotelId,
                                        htHotelStdInfo.getHotelId()));

                        // 房型
                        DossenGetHotelRoomTypeReq req = new DossenGetHotelRoomTypeReq();
                        req.setHotelId(dossenHotelData.getHotelId());
                        // Thread.sleep(1000);
                        // 获取酒店房型
                        List<DossenRoomTypeData> hotelRoomType = dossenService.getHotelRoomType(appId, key, req);
                        // 保存房型
                        hotelRoomType.forEach(roomTypeData -> {
                            HtRoomTypeStdInfo roomTypeStdInfo = new HtRoomTypeStdInfo();
                            roomTypeStdInfo.setHotelId(dossenService.parseInnId(dossenHotelData.getHotelId()));
                            roomTypeStdInfo.setRoomTypeCode(roomTypeData.getRoomTypeId());
                            roomTypeStdInfo.setRoomTypeName(roomTypeData.getRoomTypeName());
                            roomTypeStdInfo.setRoomArea(AreaUtil.parseRoomArea(roomTypeData.getAreaDesc()));
                            roomTypeStdInfo.setFloor(roomTypeData.getFloor());
                            Integer bedType = null;
                            if (StringUtils.isNotBlank(roomTypeData.getBedDes())) {
                                switch (roomTypeData.getBedDes()) {
                                    case "大床":
                                        bedType = 0;
                                        break;
                                    case "单人床":
                                        bedType = 1;
                                        break;
                                    case "双床":
                                        bedType = 2;
                                        break;
                                    case "特大床":
                                        bedType = 3;
                                        break;
                                    case "双人床":
                                        bedType = 4;
                                        break;
                                    default:
                                        bedType = 5;
                                        break;
                                }
                            }
                            roomTypeStdInfo.setBedType(bedType);
                            roomTypeStdInfo.setExtra(JsonUtil.toString(roomTypeData));
                            htRoomTypeStdInfoService.saveOrUpdate(roomTypeStdInfo,
                                    new LambdaQueryWrapper<HtRoomTypeStdInfo>().eq(HtRoomTypeStdInfo::getHotelId,
                                            roomTypeStdInfo.getHotelId())
                                            .eq(HtRoomTypeStdInfo::getRoomTypeCode, roomTypeStdInfo.getRoomTypeCode()));

                        });
                    }
                    getHotelInfoReq.setPageIndex(++pageIndex);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private HtHotelStdInfo buildHotelStdInfo(DossenHotelData data) {
        HtHotelStdInfo info = new HtHotelStdInfo();
        info.setSourceCode(SourceEnum.DOSSEN.getCode());
        info.setHotelId(dossenService.parseInnId(data.getHotelId()));
        BaseInfoDTO baseData = data.getBaseInfo();
        info.setHotelName(baseData.getName());
        info.setHotelNameEn(baseData.getPinyin());
        info.setBrandCode(baseData.getBrandName());
        String branName = "";
        if (StringUtils.isNotBlank(baseData.getBrandName())) {
            switch (baseData.getBrandName().toUpperCase()) {
                case "BD":
                    branName = "铂顿";
                    break;
                case "BM":
                    branName = "柏曼";
                    break;
                case "CSBJ":
                    branName = "城市便捷";
                    break;
                case "CSJX":
                    branName = "城市精选";
                    break;
                case "DY":
                    branName = "殿影";
                    break;
                case "FTD":
                    branName = "锋态度";
                    break;
                case "JC":
                    branName = "瑾程";
                    break;
                case "JT":
                    branName = "精途";
                    break;
                case "YC":
                    branName = "怡程";
                    break;
                case "YM":
                    branName = "隐沫";
                    break;
                case "YS":
                    branName = "宜尚";
                    break;
                case "YSP":
                    branName = "宜尚PLUS";
                    break;
                default:
                    break;
            }
        }

        info.setBrandName(branName);
        info.setHotelAddress(baseData.getAddr());
        info.setHotelTel(baseData.getTel());
        info.setProvinceName(data.getProvinceName());
        info.setCityName(data.getCityName());
        info.setIntroduction(baseData.getDescription());
        Integer restaurant = null;
        if (StringUtils.isNotBlank(baseData.getDiannei())) {
            restaurant = baseData.getDiannei().contains("有早餐") ? 1 : 0;
        }
        info.setSupportRestaurant(restaurant);
        info.setLatitude(
                StringUtils.isNotBlank(baseData.getLatitude()) ? new BigDecimal(baseData.getLatitude().trim()) : null);
        info.setLongitude(
                StringUtils.isNotBlank(baseData.getLongitude()) ? new BigDecimal(baseData.getLongitude().trim()) : null);
        info.setMapPointType(0);
        info.setExtra(JsonUtil.toString(data));
        return info;
    }

    @Override
    public void syncDossenRatesTaskPush() {
        try {
            List<HtHotelStdInfo> htHotelStdInfos = htHotelStdInfoDao.selectList(
                    new LambdaQueryWrapper<HtHotelStdInfo>().eq(HtHotelStdInfo::getSourceCode,
                            SourceEnum.DOSSEN.getCode()));
            if (CollectionUtils.isNotEmpty(htHotelStdInfos)
                    && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_MAIN_DOSSEN_RATES_LIST) <= 0) {
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_DOSSEN_RATES_LIST,
                        htHotelStdInfos.stream().map(HtHotelStdInfo::getHotelId).collect(Collectors.toList()));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void syncDossenLongerRatesTaskPush() {
        try {
            List<HtHotelStdInfo> htHotelStdInfos = htHotelStdInfoDao.selectList(
                    new LambdaQueryWrapper<HtHotelStdInfo>().eq(HtHotelStdInfo::getSourceCode,
                            SourceEnum.DOSSEN.getCode()));
            if (CollectionUtils.isNotEmpty(htHotelStdInfos)
                    && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_MAIN_DOSSEN_LONGER_RATES_LIST) <= 0) {
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_DOSSEN_LONGER_RATES_LIST,
                        htHotelStdInfos.stream().map(HtHotelStdInfo::getHotelId).collect(Collectors.toList()));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void syncDossenRatesTaskFastPop(String appId, String key, Integer days, Integer cardLevel,
                                           String activityCode) {
        syncDossenRatesTaskPopPool.execute(
                () -> new SyncDossenRatesTaskThread(appId, key, days, cardLevel, activityCode));
    }

    @Override
    public void syncDossenLongerRatesTaskFastPop(String appId, String key, Integer addDays, Integer days, Integer cardLevel, String activityCode) {
        syncDossenLongerRatesTaskPopPool.execute(
                () -> new SyncDossenLongerRatesTaskThread(appId, key, addDays, days, cardLevel, activityCode));
    }

    @Override
    public void syncDossenHotspotRatesTaskPush() {
        try{
            List<String> hotels = hworldCallBackClient.getHotspotHotels().stream()
                    .filter(e -> e.startsWith(SourceEnum.DOSSEN.getCode())).collect(Collectors.toList());
            if(com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(hotels)
                    && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_MAIN_DOSSEN_HOTSPOT_RATES_LIST) <= 0){
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_DOSSEN_HOTSPOT_RATES_LIST,
                        new ArrayList<>(hotels));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void syncDossenHotspotRatesTaskFastPop(String appId, String key, Integer days, Integer cardLevel, String activityCode) {
        syncDossenHotspotRatesTaskPopPool.execute(
                () -> new SyncDossenHotspotRatesTaskThread(appId, key, days, cardLevel, activityCode));
    }

    @Override
    public void syncDossenRatesTaskPop(String appId, String key, String hotelId, Date start, Date end,
                                       Integer cardLevel, String activityCode) {
        // 创建 SimpleDateFormat 对象，指定日期格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        DossenGetPriceAndCountReq req = new DossenGetPriceAndCountReq();
        req.setHotelId(hotelId);
        req.setCheckInDay(dateFormat.format(start));
        req.setCheckOutDay(dateFormat.format(end));
        req.setActivityCode(activityCode);
        // 找到当前酒店在中台数据库中的记录 先按房型码排序 再按日期排序
        List<HtPriceCalendar> htPriceCalendars = htPriceCalendarService.list(new LambdaQueryWrapper<HtPriceCalendar>()
                .eq(HtPriceCalendar::getHotelId, dossenService.parseInnId(hotelId))).stream()
                .sorted(Comparator.comparing(HtPriceCalendar::getRoomTypeCode)
                        .thenComparing(HtPriceCalendar::getCalDate))
                .collect(Collectors.toList());
        AtomicBoolean incrFlag = new AtomicBoolean(false);
        // 存在当前数据库中的房型
        List<String> memoryRoomTypes = htPriceCalendars.stream()
                .map(HtPriceCalendar::getRoomTypeCode)
                .distinct().collect(Collectors.toList());

        while (true) {
            if (StringUtils.isNotBlank(
                    redisUtil.acquireToken(RedisKeyConstant.HOTEL_MAIN_DOSSEN_ROOM_STATUS_LIMIT_LOCK,
                            QPS_COUNT,
                            TIME_OUT))) {
                Integer breakfastCount = dossenService.getBreakfastCount(appId, key, hotelId, activityCode);
                String rpCacheKey =
                        String.format("%s_%s_%s", RedisKeyConstant.HOTEL_MAIN_DOSSEN_RP_CACHE, appId, activityCode);
                DossenRatePlanData dossenRatePlanData = (DossenRatePlanData) redisUtil.get(rpCacheKey);
                List<DossenPriceAndCountData> priceAndCount = dossenService.getPriceAndCount(appId, key, req);
                try {
                    // 将当前从接口中拿到的所有房型码变成一个list去跟数据库中的取差集
                    List<String> tempRoomTypes = priceAndCount.stream()
                            .map(DossenPriceAndCountData::getRoomTypeId)
                            .collect(Collectors.toList());
                    memoryRoomTypes.removeAll(tempRoomTypes);
                    if (CollectionUtils.isNotEmpty(memoryRoomTypes)) {
                        incrFlag.set(true);
                        memoryRoomTypes.forEach(roomTypeCode-> {
                            // 库存刷为0
                            updateQuota(dossenService.parseInnId(hotelId), roomTypeCode);
                        });
                    }
                } catch (Exception e) {
                    log.error("roomStatus-compare-error");
                }
                priceAndCount.forEach(data -> {
                    ActivityResvRoomDTO activityResvRoomDTO = new ActivityResvRoomDTO();
                    if (StringUtils.isBlank(activityCode)) {
                        ActivityResvRoomDTO getData = data.getActivityResvRoomList().stream().findAny().orElse(new ActivityResvRoomDTO());
                        BeanUtil.copyProperties(getData, activityResvRoomDTO);
                    } else {
                        activityResvRoomDTO =
                                Optional.ofNullable(data.getActivityResvRoomList())
                                        .orElse(new ArrayList<>())
                                        .stream()
                                        .filter(dto -> org.apache.commons.lang3.StringUtils.isNotBlank(
                                                activityCode)
                                                && activityCode.equals(dto.getActivityCode()))
                                        .findFirst().orElse(null);
                        // 取不到
                        if (activityResvRoomDTO == null) {
                            activityResvRoomDTO = new ActivityResvRoomDTO();
                            ActivityResvRoomDTO getData = data.getActivityResvRoomList().stream().findAny().orElse(new ActivityResvRoomDTO());
                            BeanUtil.copyProperties(getData, activityResvRoomDTO);
                            // 找不到活动码就先库存为1关房 防止出现找不到活动价的情况
                            activityResvRoomDTO.setUsableCount(1);
                        }
                    }

                    // build 参数
                    HtPriceCalendar htPriceCalendar = new HtPriceCalendar();
                    htPriceCalendar.setHotelId(dossenService.parseInnId(hotelId));
                    htPriceCalendar.setRoomTypeCode(data.getRoomTypeId());
                    htPriceCalendar.setRoomTypeName(data.getRoomTypeName());
                    try {
                        htPriceCalendar.setCalDate(new SimpleDateFormat("yyyy-MM-dd").parse(data.getBizDay2()));
                    } catch (ParseException e) {
                        throw new RuntimeException(e);
                    }

                    htPriceCalendar.setQuota(activityResvRoomDTO.getUsableCount());
                    htPriceCalendar.setRetailPrice(data.getRackRate());
                    htPriceCalendar.setPurchasePrice(activityResvRoomDTO.getRoomPrice());

                    // 没有变化的时候才走
                    if (!incrFlag.get()) {
                        // 获取当前房型 在当前日 中台的数据
                        HtPriceCalendar roomCalDatePriceCalendar =
                                getRoomCalDatePriceCalendar(htPriceCalendar.getRoomTypeCode(), htPriceCalendar.getCalDate(), htPriceCalendars);
                        incrFlag.set(validatePrice(htPriceCalendar.getRetailPrice(), htPriceCalendar.getPurchasePrice(), htPriceCalendar.getQuota(), roomCalDatePriceCalendar));
                    }

                    htPriceCalendar.setBreakfastCount(breakfastCount);
                    htPriceCalendar.setCancelRule(
                            Optional.ofNullable(dossenRatePlanData).map(DossenRatePlanData::getCancelPolicy)
                                    .orElse(null));
                    // 保存房态信息
                    htPriceCalendarService.saveOrUpdate(htPriceCalendar,
                            new LambdaQueryWrapper<HtPriceCalendar>().eq(HtPriceCalendar::getHotelId,
                                    htPriceCalendar.getHotelId())
                                    .eq(HtPriceCalendar::getRoomTypeCode, htPriceCalendar.getRoomTypeCode())
                                    .eq(HtPriceCalendar::getCalDate, htPriceCalendar.getCalDate()));
                });
                break;
            }
        }

        // 如果当前酒店是增量酒店 调用接口通知各渠道
        if (incrFlag.get()) {
            log.info("main-incrHotel={}", dossenService.parseInnId(hotelId));
            // TODO send mq
            incrHotelRocketMqProducer.send(dossenService.parseInnId(hotelId));
        }
    }

    @Override
    public void syncDossenRoomRepairPush() {
        try{
            List<String> hotels = hworldCallBackClient.getHotspotHotels().stream()
                    .filter(e -> e.startsWith(SourceEnum.DOSSEN.getCode())).collect(Collectors.toList());
            if(com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(hotels)
                    && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_MAIN_DOSSEN_ROOM_REPAIR_LIST) <= 0){
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_DOSSEN_ROOM_REPAIR_LIST,
                        new ArrayList<>(hotels));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void syncDossenRoomRepairPop(String appId, String key, Integer cardLevel, String activityCode) {
        syncDossenRoomRepairTaskPopPool.execute(
                () -> new SyncDossenRoomRepairThread(appId, key, cardLevel, activityCode));
    }

    @Override
    public void syncDossenRoomRepair(String appId, String key, String hotelId, Date start, Date end, Integer cardLevel, String activityCode) {
        // 将当前酒店下所有房型全部置为不可售
        htRoomTypeStdInfoService.update(null,
                new LambdaUpdateWrapper<HtRoomTypeStdInfo>()
                        .set(HtRoomTypeStdInfo::getRoomStatus, 0)
                        .eq(HtRoomTypeStdInfo::getHotelId, hotelId));
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        DossenGetPriceAndCountReq req = new DossenGetPriceAndCountReq();
        req.setHotelId(hotelId);
        req.setCheckInDay(dateFormat.format(start));
        req.setCheckOutDay(dateFormat.format(end));
        req.setActivityCode(activityCode);

        while (true) {
            if (StringUtils.isNotBlank(
                    redisUtil.acquireToken(RedisKeyConstant.HOTEL_MAIN_DOSSEN_ROOM_STATUS_LIMIT_LOCK,
                            QPS_COUNT,
                            TIME_OUT))) {
                List<DossenPriceAndCountData> priceAndCount = dossenService.getPriceAndCount(appId, key, req);
                priceAndCount.forEach(data -> {
                    // 将获取到房态的房型状态改为1
                    htRoomTypeStdInfoService.update(null,
                            new LambdaUpdateWrapper<HtRoomTypeStdInfo>()
                                    .set(HtRoomTypeStdInfo::getRoomStatus, 1)
                                    .eq(HtRoomTypeStdInfo::getHotelId, dossenService.parseInnId(hotelId))
                                    .eq(HtRoomTypeStdInfo::getRoomTypeCode, data.getRoomTypeId()));
                });
                break;
            }
        }
    }

    @Override
    public void syncDossenPicPush() {
        if (redisUtil.setENx(RedisKeyConstant.HOTEL_MAIN_DOSSEN_PIC_PUSH,PUSH_EXPIRY,
                RedisKeyConstant.HOTEL_MAIN_DOSSEN_PIC_PUSH)) {
            List<String> hotelIds = htHotelStdInfoDao.selectList(new LambdaQueryWrapper<HtHotelStdInfo>()
                    .eq(HtHotelStdInfo::getSourceCode, SourceEnum.DOSSEN.getCode())
                    .eq(HtHotelStdInfo::getSourceStatus, 1)
                    .eq(HtHotelStdInfo::getBookStatus, 1))
                    .stream().map(HtHotelStdInfo::getHotelId)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(hotelIds)
                    && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_MAIN_DOSSEN_PIC_LIST) <= 0) {
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_DOSSEN_PIC_LIST, new ArrayList<>(hotelIds));
            }
        }
    }

    @Override
    public void syncDossenPicPop(String sourceAppId, String sourceSecret) {
        syncDossenHotelIdListTaskFastPopPool.execute( () -> new SyncDossenPicTaskThread(sourceAppId, sourceSecret));

    }

    @Override
    public void syncDossenPic(String appId, String secret, String hotelId) {
        String baseUrl = "https://resource.dossen.com/StaticFile";
        while (true) {
            if (StringUtils.isNotBlank(redisUtil.acquireToken(RedisKeyConstant.HOTEL_MAIN_DOSSEN_ROOM_STATUS_LIMIT_LOCK,
                    QPS_COUNT,
                    TIME_OUT))) {

                // 酒店请求
                DossenGetHotelInfoReq hotelInfoParam = DossenGetHotelInfoReq.builder()
                        .hotelId(dossenService.parseHotelId(hotelId))
                        .pageSize(1)
                        .pageIndex(1)
                        .build();
                DossenHotelData hotelData = dossenService.getHotelInfo(appId, secret, hotelInfoParam).getRecords().get(0);
                BaseInfoDTO baseInfo = hotelData.getBaseInfo();

                List<HtHotelStdImage> hotelImages = htHotelStdImageService.list(new LambdaQueryWrapper<HtHotelStdImage>()
                        .eq(HtHotelStdImage::getHotelId, hotelId)
                        .eq(HtHotelStdImage::getImageType, 2));
                if (CollectionUtils.isEmpty(hotelImages)) {
                    saveHotelImages(baseInfo, hotelId);
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ignore) {
                }
                // 房型请求
                DossenGetHotelRoomTypeReq roomTypeParam = DossenGetHotelRoomTypeReq.builder()
                        .hotelId(dossenService.parseHotelId(hotelId))
                        .build();
                List<DossenRoomTypeData> hotelRoomType = dossenService.getHotelRoomType(appId, secret, roomTypeParam);
                // 房型图落库
                Optional.ofNullable(hotelRoomType).orElse(new ArrayList<>()).forEach(roomTypeData -> {
                    List<HtHotelStdImage> roomImages = htHotelStdImageService.list(new LambdaQueryWrapper<HtHotelStdImage>()
                            .eq(HtHotelStdImage::getHotelId, hotelId)
                            .eq(HtHotelStdImage::getRoomTypeCode, roomTypeData.getRoomTypeId())
                            .eq(HtHotelStdImage::getImageType, 3));

                    if (CollectionUtils.isEmpty(roomImages)) {
                        savePicInfo(hotelId, roomTypeData.getRoomTypeId(), 3, baseUrl+roomTypeData.getThumbnailUrl(), "");
                    }
                });
                break;
            }
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignore) {
        }
    }


    private Boolean validatePrice(BigDecimal retailPrice, BigDecimal purchasePrice, Integer quota, HtPriceCalendar htPriceCalendar) {
        if (Objects.isNull(htPriceCalendar)) {
            return true;
        }
        boolean flag = false;

        if (Objects.nonNull(htPriceCalendar.getQuota())  && Objects.nonNull(quota)) {
            flag = !htPriceCalendar.getQuota().equals(quota) && quota <= 10;
        }

        if (Objects.nonNull(htPriceCalendar.getRetailPrice()) && Objects.nonNull(retailPrice)) {
            flag = htPriceCalendar.getRetailPrice().compareTo(retailPrice) != 0 || flag;
        }

        if (Objects.nonNull(htPriceCalendar.getPurchasePrice()) && Objects.nonNull(purchasePrice)) {
            flag =  htPriceCalendar.getPurchasePrice().compareTo(purchasePrice) != 0 || flag;
        }

        return flag;
    }

    private HtPriceCalendar getRoomCalDatePriceCalendar(String roomType, Date date, List<HtPriceCalendar> htPriceCalendars) {
        return htPriceCalendars.stream()
                .filter(e -> e.getRoomTypeCode().equals(roomType)
                        && DateUtils.isSameDay(e.getCalDate(), date))
                .findFirst().orElse(null);
    }

    private void updateQuota(String hotelId, String roomTypeCode) {
        htPriceCalendarService.update(null, new LambdaUpdateWrapper<HtPriceCalendar>()
                .set(HtPriceCalendar::getQuota, 0)
                .eq(HtPriceCalendar::getHotelId, hotelId)
                .eq(HtPriceCalendar::getRoomTypeCode, roomTypeCode));
    }

    private void saveHotelImages(BaseInfoDTO baseInfo, String hotelId) {
        if (StringUtils.isNotBlank(baseInfo.getPic()) && baseInfo.getPic().contains("image")) {
            savePicInfo(hotelId,"",1, baseInfo.getPic(), "");
            savePicInfo(hotelId,"",2, baseInfo.getPic(), "");
        }
        if (StringUtils.isNotBlank(baseInfo.getPic1()) && baseInfo.getPic1().contains("image")) {
            savePicInfo(hotelId,"",2, baseInfo.getPic1(), "");
        }
        if (StringUtils.isNotBlank(baseInfo.getPic2()) && baseInfo.getPic2().contains("image")) {
            savePicInfo(hotelId,"",2, baseInfo.getPic2(), "");
        }
        if (StringUtils.isNotBlank(baseInfo.getPic3()) && baseInfo.getPic3().contains("image")) {
            savePicInfo(hotelId,"",2, baseInfo.getPic3(), "");
        }
        if (StringUtils.isNotBlank(baseInfo.getPic4()) && baseInfo.getPic4().contains("image")) {
            savePicInfo(hotelId,"",2, baseInfo.getPic4(), "");
        }
        if (StringUtils.isNotBlank(baseInfo.getPic5()) && baseInfo.getPic5().contains("image")) {
            savePicInfo(hotelId,"",2, baseInfo.getPic5(), "");
        }
    }

    private void savePicInfo(String hotelId, String roomTypeCode, Integer type, String sourceUrl, String imageUrl) {
        HtHotelStdImage image = new HtHotelStdImage();
        image.setHotelId(hotelId);
        image.setRoomTypeCode(roomTypeCode);
        image.setImageType(type);
        image.setSourceUrl(sourceUrl);
        image.setImageUrl(imageUrl);
        htHotelStdImageService.save(image);
    }
}
